#!/bin/bash

# splint 代码检查脚本：自动搜索所有include目录作为头文件路径，所有src目录作为源文件路径
# 支持输出报告文件、详细模式和严格检查模式

# 初始化默认值
REPORT_FILE="report_splint_$(date +%Y%m%d_%H%M%S).txt"  # 报告文件（含时间戳）
VERBOSE=0                  # 详细输出模式（0=关闭，1=开启）
STRICT_MODE=0              # 严格检查模式（0=关闭，1=开启）
BASE_DIR="./"              # 基础搜索目录
APPPEND_INC="./"

# 显示帮助信息
show_help() {
    cat << EOF
Usage: $(basename "$0") [options]

Options:
  -b, --base <directory>    Specify base directory for search (default: ./)
  -o, --output <file>       Specify the report output file (default: timestamped report file)
  -i, --include <dirstack>  Specify include directory (default: ./)
  -v, --verbose             Enable verbose output mode
  -s, --strict              Enable strict checking mode (more warnings)
  -h, --help                Show this help message

Examples:
  $(basename "$0") -b ./project_root -o check_report.txt
  $(basename "$0") --strict --verbose
EOF
}

# 解析命令行参数
parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -b|--base)
                BASE_DIR="$2"
                shift 2
                ;;
            -o|--output)
                REPORT_FILE="$2"
                shift 2
                ;;
            -i|--include)
                APPPEND_INC="$APPPEND_INC"$'\n'"$2"
                shift 2
                ;;
            -v|--verbose)
                VERBOSE=1
                shift
                ;;
            -s|--strict)
                STRICT_MODE=1
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            *)
                echo "Error: Unknown option '$1'" >&2
                show_help >&2
                exit 1
                ;;
        esac
    done
}

# 检查依赖工具是否安装
check_dependencies() {
    if ! command -v splint &> /dev/null; then
        echo "Error: splint tool not found, please install it first." >&2
        echo "Installation methods:" >&2
        echo "  Ubuntu/Debian: sudo apt-get install splint" >&2
        echo "  CentOS/RHEL: sudo yum install splint" >&2
        echo "  macOS: brew install splint" >&2
        exit 1
    fi
}

# 验证基础目录是否存在
validate_base_directory() {
    if [[ ! -d "$BASE_DIR" ]]; then
        echo "Error: Base directory '$BASE_DIR' does not exist." >&2
        exit 1
    fi
}

# 自动搜索所有include和src目录
discover_directories() {
    echo "Searching for source and header directories in $BASE_DIR..."
    
    # 搜索所有src目录（源文件）
    SRC_DIRS=$(find "$BASE_DIR" -type d -name "src")
    
    # 搜索所有include目录（头文件）
    INCLUDE_DIRS=$(find "$BASE_DIR" -type d -name "include")
    INCLUDE_DIRS="$INCLUDE_DIRS"$'\n'"$APPPEND_INC"
    
    # 检查是否找到目录
    if [[ -z "$SRC_DIRS" ]]; then
        echo "Error: No 'src' directories found in $BASE_DIR" >&2
        exit 1
    fi
    
    if [[ -z "$INCLUDE_DIRS" ]]; then
        echo "Warning: No 'include' directories found in $BASE_DIR" >&2
    fi
    
    # 详细模式下显示找到的目录
    if [[ $VERBOSE -eq 1 ]]; then
        echo "Found source directories (src):"
        echo "$SRC_DIRS" | while read -r dir; do
            echo "  - $dir"
        done
        
        echo "Found header directories (include):"
        echo "$INCLUDE_DIRS" | while read -r dir; do
            echo "  - $dir"
        done
        echo "-------------------------"
    fi
}

# 收集所有要检查的C文件
collect_files() {
    echo "Collecting all C files from source directories..."
    C_FILES=$(find $SRC_DIRS -type f -name "*.c")
        

    if [[ -z "$C_FILES" ]]; then
        echo "Warning: No .c files found in source directories."
        exit 0
    fi

    echo "$C_FILES" | while read -r file; do
        echo "$file"
    done

    echo "$INCLUDE_DIRS" | while read -r file; do
        echo "include: $file"
    done

    if [[ $VERBOSE -eq 1 ]]; then
        echo "List of found C files:"
        echo "$C_FILES" | while read -r file; do
            echo "  - $file"
        done
        echo "-------------------------"
    fi
}

# 执行splint检查
run_splint_check() {
    echo "Starting splint code inspection..."
    echo "Check results will be saved to: $REPORT_FILE"

    # 构建头文件路径选项
    SPLINT_OPTS=""
    for dir in $INCLUDE_DIRS; do
        # 过滤掉工具链相关的头文件目录
        if [[ ! "$dir" =~ "staging_dir/toolchain-" ]]; then
            SPLINT_OPTS="$SPLINT_OPTS -I$dir"
        fi
    done

    SPLINT_OPTS="$SPLINT_OPTS \
    -D__linux__ \
    -D__builtin_va_list=va_list \
    -D__signed__=signed \
    +gnuextensions"
    

    # 添加严格模式选项
    if [[ $STRICT_MODE -eq 1 ]]; then
        SPLINT_OPTS="$SPLINT_OPTS -strict"
    fi

    # 执行检查并输出到报告文件
    {
        echo "=== Splint Code Check Report ==="
        echo "Check time: $(date)"
        echo "Base directory: $BASE_DIR"
        echo "Source directories: $SRC_DIRS"
        echo "Header directories: $INCLUDE_DIRS"
        echo "Options used: $SPLINT_OPTS"
        echo "==========================="
        echo ""

        # 对每个文件执行检查
        echo "$C_FILES" | while read -r file; do
            echo "----------------------------------------"
            echo "Checking file: $file"
            echo "----------------------------------------"
            splint $SPLINT_OPTS "$file"
            echo ""  # 增加空行分隔不同文件的结果
        done

        echo "=== Check Completed ==="
        echo "Total files checked: $(echo "$C_FILES" | wc -l | tr -d ' ')"
        echo "Report generated at: $(date)"
    } > "$REPORT_FILE"

    # 如果启用详细模式，同时输出到控制台
    if [[ $VERBOSE -eq 1 ]]; then
        cat "$REPORT_FILE"
    fi
}

# 显示检查摘要
show_summary() {
    echo "-------------------------"
    echo "Code check completed!"
    echo "Report saved to: $REPORT_FILE"
    
    # 统计错误和警告数量（简单分析）
    # ERROR_COUNT=$(grep -c "Error:" "$REPORT_FILE")
    # WARNING_COUNT=$(grep -c "Warning:" "$REPORT_FILE")
    ERROR_COUNT=$(grep -c -E "Error:|*** Cannot continue|Fatal bug" "$REPORT_FILE")
    WARNING_COUNT=$(grep -c -E "warning|code warnings" "$REPORT_FILE")
    
    echo "Errors found: $ERROR_COUNT"
    echo "Warnings found: $WARNING_COUNT"
    echo "-------------------------"
}

# 主函数
main() {
    parse_args "$@"
    check_dependencies
    validate_base_directory
    discover_directories
    collect_files
    run_splint_check
    show_summary
}

# 启动主函数
main "$@"

